# -*- coding: utf-8 -*-


# cmap2owl -- Helper application to convert from concept maps to OWL ontologies
# Copyright (c) 2008-2013  Rodrigo Rizzi Starr
#  
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#  
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#  
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


'''
Contains a set of rules to identify necessary and sufficient conditions for
class membership

@author: Rodrigo Rizzi Starr
@copyright: Copyright © 2008-2013 Rodrigo Rizzi Starr
@license: MIT License
@contact: rodrigo.starr@gmail.com
'''


from CMap2Prolog import assemblyQuery
from mapperRule import MapperRule
from mapperQuestion import MapperQuestion
#from toogleQuestion import ToogleQuestion
from infoProvider import SimpleInfoProvider, UnionOfInfoProviders
from log import log
log.debug("Loaded...")


class SufficientRule(MapperRule):
    """Looks for conditions that may indicate a sufficient condition for
        classification"""
    
    def __init__(self, db):
        
        classifiers = [
                        ]
        
        # Heuristics to identify generalization/specialization rules
        rules = [
                 "inferenceGroup(sufficientRule,"
                    "[sufficient(_)])",
                 
                 
                 "sufficient(hasPart(Relation, Owner, PartSet)) :-"
                    "isTrue(hasPart(Relation, Owner, PartSet))",
                    
                 # Consequences
                 "hasPartSufficientClassesOWL(Class, ClassSet) :-"
                   "isTrue(sufficient(hasPart(_, Class, ClassSet)))",
                    ]
         
        MapperRule.__init__(self, "SufficientRule", db, rules, classifiers)
          
    def getHasPartQuestions(self):
        "Returns a list of questions related to hasPart relations"
        
        questions = []
        query = "sufficient(hasPart(Relation, FromClass, ToSet))"
        relations = list(self.db.query(query))
        
        for answer in relations:
            questions.append(SufficientHasPartQuestion(
                self.db,
                answer,
                'Can i say that any thing that has "<b>%(ToSet)s</b>" as parts '
                    ' is of type "<b>%(FromClass)s</b>" ?',
                "sufficient(hasPart(%(Relation)s, %(FromClass)s, %(ToSet)s))",
                helpFile='sufficient',
                 ))
            
        return questions
      
    def getQuestions(self):
        "Returns a question's list"
        
        questions = []
        
        questions.extend(self.getHasPartQuestions())
            
        return questions
      
    def getInfoProvider(self):
        "Returns an info provider about mereological relations"
        
        hasPartInfo = SimpleInfoProvider(self.db,
                            "isTrue(sufficient(hasPart(_, %s, Set)))",
                            "Any individual composed of the following parts " \
                                "is an instance of this class.")
        
        return UnionOfInfoProviders(hasPartInfo)

    
class SufficientHasPartQuestion(MapperQuestion):
    "Implements a better way of checking the has part relationship"
    
    def updateQueryData(self):
        "Creates a string representing a query"
        query = "possible(sufficient(" \
                "hasPart(%(Relation)s, %(FromClass)s, NewSet)))," \
                "subset(%(ToSet)s, NewSet)"
        
        self.queryData = assemblyQuery(query, self.data)
    
    def updateIds(self):
        "Return a set of updated ids"
        
        answer = list(self.db.query(self.queryIds))
        if len(answer) > 1:
            log.error("The answer for " + self.queryIds + 
                      " was more than 1 result long. This is weird.")
        elif len(answer) == 0:
            self.ids = set()
        else:
            answer = answer[0]['NewSet']
            self.data['NewSet'] = answer
            self.ids = set(answer)
            self.ids.add(self.data['Relation'])
            self.ids.add(self.data['FromClass'])
                       
    def assertOnYes(self):
        "Asserts an updated set of elements"
        
        queries = [assemblyQuery(
                    'isTrue(sufficient(' \
                        'hasPart(%(Relation)s, %(FromClass)s, %(NewSet)s)))',
                    self.data)]
        
        return queries
    
    def assertOnNo(self):
        "Creates a string representing a question"
        
        queries = assemblyQuery(
                    'isFalse(sufficient(' \
                        'hasPart(%(Relation)s, %(FromClass)s, %(NewSet)s)))',
                    self.data)
        
        return [queries]
      
